﻿// -----------------------------------------------------------------------
// <copyright file="GateShiftService.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
// -----------------------------------------------------------------------
#region Usings

using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using GateShift.Servers.GameServer.HelperClasses;
using GateShift.Servers.GameServer.LoggingSystem;
using GateShift.Servers.GameServer.Managers.Connection;
using GateShift.Servers.GameServer.Managers.Consoles;
using GateShift.Servers.GameServer.Managers.Service;
using GateShift.Servers.GameServer.Managers.Session;

#endregion

namespace GateShift.Servers.GameServer.Core
{
    /// <summary>
    /// Windows Service class for the GateShift Service
    /// </summary>
    internal partial class GateShiftService : ServiceBase
    {
        #region Variables

        private readonly ServerHost _serverHost;
        private Thread _backendThread;
        private ConsoleManager _consoleManager;
        private ServiceManager _serviceManager;
        private SessionManager _sessionManager;
        private ConnectionManager _connectionManager;

        #endregion

        #region CTor/DTor

        /// <summary>
        /// Initializes a new instance of the GateShiftService class
        /// </summary>
        public GateShiftService()
        {
            InitializeComponent();

            _serverHost = new ServerHost();
        }

        #endregion

        /// <summary>
        /// Gets a value indicating whether or not the service status shows it is running
        /// </summary>
        public bool IsAlive
        {
            get { return _backendThread != null && _backendThread.IsAlive; }
        }

        /// <summary>
        /// Manual start for non service startups
        /// </summary>
        internal void Start()
        {
            OnStart(null);
        }

        #region Service Methods

        /// <summary>
        /// Method for starting via Windows Services
        /// </summary>
        /// <param name="args">string Array of all arguments passed from the Windows Service interface</param>
        protected override void OnStart(string[] args)
        {
            _backendThread = new Thread(ProcessLoop);
            _backendThread.Start();

            base.OnStart(args);
        }

        /// <summary>
        /// Method for stopping via Windows Services
        /// </summary>
        protected override void OnStop()
        {
            _backendThread.Abort();
            RequestAdditionalTime(60000);
            _backendThread.Join();

            base.OnStop();
        }

        #endregion

        #region Thread Functions

        /// <summary>
        /// Background thread that handles all the main parts to the service.
        /// </summary>
        private void ProcessLoop()
        {
            if (SystemGlobals.ConsoleMode)
            {
                _consoleManager = new ConsoleManager();
            }

            _sessionManager = new SessionManager();
            _serviceManager = new ServiceManager();
            _connectionManager = new ConnectionManager();

            try
            {
                // Capture global logs
                Log.EventLogged += Log_EventLogged;

                SetReferences();

                Log.AddEntry("Starting", "Manager Sub-System Starting", LogPriorities.Verbose, TraceEventType.Information, (int)CoreLogCategories.SystemCore);
                StartManagers();

                Log.AddEntry("Initializing", "Manager Sub-System Initializing", LogPriorities.Verbose, TraceEventType.Information, (int)CoreLogCategories.SystemCore);
                InitializeManagers();

                if (SystemGlobals.ConsoleMode)
                {
                    Log.AddEntry("Initializing", "Adding Console Command Handlers", LogPriorities.Verbose, TraceEventType.Information, (int)CoreLogCategories.SystemCore);
                    AddConsoleHandlers();
                }

                Thread.Sleep(Timeout.Infinite);
            }
            catch (ThreadAbortException)
            {
                Log.AddEntry("Stopping", "Manager Sub-System Stopping", LogPriorities.Verbose, TraceEventType.Information, (int)CoreLogCategories.SystemCore);
                StopManagers();
            }
        }

        #endregion

        #region Manager Sub-System

        /// <summary>
        /// Set required references for the managers
        /// </summary>
        private void SetReferences()
        {
            // Set up ServerHost
            _serverHost.ServiceHost = _serviceManager;
            _serverHost.SessionHost = _sessionManager;

            _sessionManager.ConnectionManager = _connectionManager;
            _serviceManager.ConnectionManager = _connectionManager;
            _serviceManager.ServerHostManager = _serverHost;

            _consoleManager.ExitRequested += ConsoleManager_ExitRequested;
        }

        /// <summary>
        /// Starts up all managers
        /// </summary>
        private void StartManagers()
        {
            if (_consoleManager != null)
            {
                _consoleManager.Start();
            }

            _sessionManager.Start();
            _connectionManager.Start();
            _serviceManager.Start();
        }

        /// <summary>
        /// Stops all managers
        /// </summary>
        private void StopManagers()
        {
            _sessionManager.Stop();
            _connectionManager.Stop();
            _serviceManager.Stop();
            //// if (_consoleManager != null)
            //// _consoleManager.Stop();
        }

        /// <summary>
        /// Initializes manager resources
        /// </summary>
        private void InitializeManagers()
        {
            if (_consoleManager != null)
            {
                _consoleManager.Initialize();
            }

            _connectionManager.Initialize();
            _sessionManager.Initialize();
            _serviceManager.Initialize();
        }

        /// <summary>
        /// Adds console command handlers to the console and admin managers
        /// </summary>
        private void AddConsoleHandlers()
        {
            if (_consoleManager == null)
            {
                return;
            }

            _consoleManager.AddCLIHandler("console", _consoleManager);
            _consoleManager.AddCLIHandler("service", _serviceManager);
            _consoleManager.AddCLIHandler("session", _sessionManager);
            _consoleManager.AddCLIHandler("connect", _connectionManager);
        }

        #endregion

        /// <summary>
        /// Event Handler for a global log being logged
        /// </summary>
        /// <param name="sender">Log Global file calling this method</param>
        /// <param name="e">LogEventArgs with information about the event</param>
        private void Log_EventLogged(object sender, LogEventArgs e)
        {
            if (_consoleManager != null)
            {
                _consoleManager.AddEventLog(e.Message);
            }
        }

        /// <summary>
        /// Event handler for the console manager requesting an exit
        /// </summary>
        /// <param name="sender">ConsoleManager calling this method</param>
        /// <param name="e">Empty EventArgs</param>
        private void ConsoleManager_ExitRequested(object sender, EventArgs e)
        {
            Stop();
            Environment.Exit(0);
        }
    }
}